package tech.yixiyun.framework.kuafu.db.sql.handler;


import com.fasterxml.jackson.databind.JavaType;
import tech.yixiyun.framework.kuafu.db.DbException;
import tech.yixiyun.framework.kuafu.db.sql.SqlException;
import tech.yixiyun.framework.kuafu.kits.ClassKit;
import tech.yixiyun.framework.kuafu.kits.DateKit;
import tech.yixiyun.framework.kuafu.kits.JSONKit;
import tech.yixiyun.framework.kuafu.kits.StringKit;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.ResultSet;
import java.sql.Time;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 列的值处理器
 */
public class ColumnProcessor {


    /**
     * 不需要做特殊处理的类
     */
    private static final Set<Class> commonColumnClasses = new HashSet<>(){
        {
            add(int.class);
            add(Integer.class);
            add(double.class);
            add(Double.class);
            add(boolean.class);
            add(Boolean.class);
            add(short.class);
            add(Short.class);
            add(char.class);
            add(Character.class);
            add(float.class);
            add(Float.class);
            add(long.class);
            add(Long.class);
            add(byte.class);
            add(Byte.class);
            add(String.class);
            add(Date.class);
            add(java.sql.Date.class);
            add(Time.class);
            add(BigDecimal.class);
            add(BigInteger.class);

        }
    };

    /**
     * 存储那些带泛型的类的 泛型参数
     */
    private static final ConcurrentHashMap<Type, Node> parameterizedMap = new ConcurrentHashMap<>();

    /**
     * 根据一个泛型类获取它的泛型参数，没有就去分析
     * @param type
     * @return
     */
    private static Node getOrResolve(ParameterizedType type) {
        return parameterizedMap.computeIfAbsent(type, t -> {
            Class raw = (Class) type.getRawType();
            Type[] types = type.getActualTypeArguments();
            Class[] args = new Class[types.length];
            for (int i = 0; i < args.length; i++) {
                args[i] = (Class) types[i];
            }
            return new Node(raw, args);
        });
    }

    /**
     * 是不是一个普通的类
     * @param clazz
     * @return
     */
    public static boolean isCommonColumnClass(Class clazz) {
        return commonColumnClasses.contains(clazz) ;
    }

    /**
     * 将查询的列结果进行转换
     * @param rs
     * @param columnLabel
     * @param type
     * @return
     */
    public static Object process(ResultSet rs, String columnLabel, Type type) {

        try {
            if (type instanceof Class) {
                Class fieldType = (Class) type;
                if (fieldType == String.class) {
                    return rs.getString(columnLabel);
                }
                if (fieldType.isPrimitive() || ClassKit.isPrimitiveWrapper(fieldType) || fieldType.isEnum()) {
                    return StringKit.convert(rs.getString(columnLabel), fieldType);
                }
                if (fieldType == Date.class ) {
                    return DateKit.parseDate(rs.getString(columnLabel));
                }
                if (fieldType == java.sql.Date.class) {
                    return rs.getDate(columnLabel);
                }
                if (fieldType == Time.class) {
                    return rs.getTime(columnLabel);
                }
                if (fieldType.isArray()) {
                    Class componentType = fieldType.getComponentType();
                    if (  componentType == byte.class ) {
                        return rs.getBytes(columnLabel);
                    }
                    if (isCommonColumnClass(componentType)) {
                        return StringKit.splitToArray(rs.getString(columnLabel), componentType);
                    }
                    return JSONKit.toObjectArray(rs.getString(columnLabel), componentType);
                }

                return JSONKit.toObject(rs.getString(columnLabel), fieldType);
            } else if (type instanceof ParameterizedType) {
                Node node = getOrResolve((ParameterizedType) type);
                return JSONKit.toObject(rs.getString(columnLabel),
                        JSONKit.getTypeFactory().constructParametricType(node.rawClass, node.argsClass));
            } else if (type  instanceof JavaType) {
                return JSONKit.toObject(rs.getString(columnLabel), (JavaType)type );
            }

            throw new DbException("无法将数据库数据识别并转换为类型【"+type+"】");



        } catch (Exception e) {
            throw new SqlException(columnLabel + "列的值进行转换时发生异常", e);
        }




    }


    /**
     * 缓存的泛型类型节点
     */
    private static class Node {
        Class rawClass;
        Class[] argsClass;

        Node(Class rawClass, Class[] argsClass) {
            this.rawClass = rawClass;
            this.argsClass = argsClass;
        }
    }



}
